
package org.lightpersist.util;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import net.jcip.annotations.Immutable;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import com.google.inject.cglib.proxy.MethodProxy;
import com.google.inject.matcher.Matcher;

/**
 * 
 * @author GL
 *
 */
@Immutable
class AopAllianceCglibAdapter implements com.google.inject.cglib.proxy.MethodInterceptor {
    private final Matcher<? super Class<?>> typeMatcher;
    private final Matcher<? super Method> methodMatcher;
    private final MethodInterceptorChain chain;


    public AopAllianceCglibAdapter(Matcher<? super Class<?>> typeMatcher,
			Matcher<? super Method> methodMatcher,
			MethodInterceptor... interceptors) {
    	this.typeMatcher = typeMatcher;
    	this.methodMatcher = methodMatcher;
    	this.chain = new MethodInterceptorChain(interceptors);
    }


	public Object intercept(final Object object, final Method method, final Object[] args,
                            final MethodProxy methodProxy) throws Throwable {
		if(typeMatcher.matches(object.getClass()) && methodMatcher.matches(method)){
			return chain.invoke(new MethodInvocation(){

	            public Method getMethod() {
	                return method;
	            }

	            public Object[] getArguments() {
	                return args;
	            }

	            public Object proceed() throws Throwable {
	            	if(Modifier.isAbstract(method.getModifiers()))
	            		return null;
	                return methodProxy.invokeSuper(object, args);
	            }

	            public Object getThis() {
	                return object;
	            }

	            public AccessibleObject getStaticPart() {
	                return method;
	            }
				
			});
		}else{
			return methodProxy.invokeSuper(object, args);
		}
		
    }
}
